﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System.IO;
using Object = UnityEngine.Object;

namespace Simulation.Framework
{
    public class ResManagerByAB : ManagerBehavior
    {
        private Dictionary<string, AssetBundle> assetBundleCache = new Dictionary<string, AssetBundle>();

        private List<string> assetBundleDownloadCache = new List<string>();

        private AssetBundleManifest assetBundleManifest;
        private string rootPath;

        #region override

        public override void Init()
        {
            assetBundleCache = new Dictionary<string, AssetBundle>();
            assetBundleDownloadCache = new List<string>();
        }

        public override void Clear()
        {
            RemoveAll();
            assetBundleDownloadCache = null;
            Resources.UnloadUnusedAssets();
            GC.Collect();
        }

        public override void Restar() { }

        #endregion

        public void LoadABRoot(string rootUrl, UnityAction<AssetBundle> onComplete)
        {
            rootPath = Path.GetDirectoryName(rootUrl) + "/";
            LoadABHelper(rootUrl, v => {
                assetBundleManifest = v.LoadAsset<AssetBundleManifest>("assetbundlemanifest");
                onComplete?.Invoke(v);
            });
        }

        public void LoadObject<T>(string bundleName, string objName, UnityAction<T> onComplete) where T : Object {
           LoadABWithDepencies(bundleName, () => {
               string bundleKey = rootPath + bundleName;
               if (assetBundleCache.ContainsKey(bundleKey)) {
                   AssetBundle assetBundle = assetBundleCache[bundleKey];
                   onComplete?.Invoke(assetBundle.LoadAsset<T>(objName));
               }
               else
                   onComplete?.Invoke(null);
           });
        }

        public void Remove(string bundleName) {
            if (assetBundleCache.ContainsKey(bundleName)) {
                assetBundleCache[bundleName].Unload(true);
                assetBundleCache.Remove(bundleName);
            }
            string url = rootPath + bundleName;
            SingleBehavior<HttpManager>.getInstance().StopDownload(url);
            if (assetBundleDownloadCache.Contains(url))
                assetBundleDownloadCache.Remove(url);
        }

        public void RemoveAll() {
            if (assetBundleCache != null) {
                foreach (var item in assetBundleCache)
                    item.Value.Unload(true);
                assetBundleCache?.Clear();
                if (assetBundleDownloadCache == null) return;
                for (int i = 0; i < assetBundleDownloadCache.Count; i++)
                    SingleBehavior<HttpManager>.getInstance().StopDownload(assetBundleDownloadCache[i]);
                assetBundleDownloadCache.Clear();
            }
        }

        private void LoadABWithDepencies(string bundleName, UnityAction onComplete)
        {
            // 检索 bundle 的引用
            string[] dependencies = assetBundleManifest.GetAllDependencies(bundleName);
            int count = 0;

            UnityAction<AssetBundle> onLoaded = v => {
                count++;
                if (count >= dependencies.Length + 1)
                    onComplete?.Invoke();
            };

            // 下载依赖
            if (dependencies != null && dependencies.Length > 0)
                for (int i = 0; i < dependencies.Length; i++) {
                    string dependBundleUrl = rootPath + dependencies[i];
                    LoadABHelper(dependBundleUrl, onLoaded);
                }

            // 下载 bundle
            string bundleUrl = rootPath + bundleName;
            LoadABHelper(bundleUrl, onLoaded);
        }

        private void LoadABHelper(string url, UnityAction<AssetBundle> response) {
            if (assetBundleCache.ContainsKey(url))
                response?.Invoke(assetBundleCache[url]);
            else {
                if (!assetBundleDownloadCache.Contains(url))
                    assetBundleDownloadCache.Add(url);
                SingleBehavior<HttpManager>.getInstance().DownLoadAssetBundle(url, (u, v) => {
                    if (assetBundleDownloadCache.Contains(u))
                        assetBundleDownloadCache.Remove(u);

                    if (v != null) {
                        assetBundleCache[url] = v;
                        response?.Invoke(v);
                    }
                    else
                        response?.Invoke(null);
                });
            }

        }
    }
}